home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / netconf / daemon.c < prev    next >
C/C++ Source or Header  |  1996-08-03  |  8KB  |  413 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <ctype.h>
  7. #include <sys/stat.h>
  8. #include <limits.h>
  9. #include <signal.h>
  10. #include "netconf.h"
  11. #include "../xconf/xconf.h"
  12. #include "netconf.m"
  13.  
  14. /*
  15.     Return != 0 if a file is missing or do not contain any configuration
  16.     line. A file containing only comments is considered empty.
  17.  
  18.     configuration file use \ for continuation and # for comments.
  19. */
  20. int file_empty (const char *fpath)
  21. {
  22.     int ret = 1;
  23.     FILE *fin = fopen (fpath,"r");
  24.     if (fin != NULL){
  25.         char buf[2000];
  26.         while (fgets_strip(buf,sizeof(buf)-1,fin,NULL)!=NULL){
  27.             char *pt = buf;
  28.             while (isspace(*pt)) pt++;
  29.             if (*pt != '\0'){
  30.                 ret = 0;
  31.                 break;
  32.             }
  33.         }
  34.         fclose (fin);
  35.     }
  36.     return ret;
  37. }
  38. /*
  39.     Information on how to manage and start a daemon (generally network)
  40.     To avoid repetition in subclasses, the destructor received no argument
  41.     and the init function complete the setup, so the object must always
  42.     be created and init() immediatly after. This is all done in
  43.     daemon_new().
  44. */
  45. PUBLIC DAEMON::DAEMON ()
  46. {
  47.     name = NULL;
  48.     path = NULL;
  49.     args = NULL;
  50.     next = NULL;
  51.     managed = override = 0;
  52. }
  53. /*
  54.     Information on how to manage and start a daemon (generally network)
  55. */
  56. PUBLIC void DAEMON::init (
  57.     int _managed,
  58.     const char *_name,
  59.     const char *buf,
  60.     DAEMON *_next)
  61. {
  62.     next = _next;
  63.     managed = (char)_managed;
  64.     char tmp[PATH_MAX];
  65.     char *pttmp = tmp;
  66.     while (*buf > ' ') *pttmp++ = *buf++;
  67.     *pttmp = '\0';
  68.     if (pttmp > tmp){
  69.         name = strdup (_name);
  70.         path = strdup (tmp);
  71.         buf = str_skip(buf);
  72.         args = strdup (buf);
  73.     }
  74.     
  75. }
  76.  
  77. PUBLIC VIRTUAL DAEMON::~DAEMON ()
  78. {
  79.     free (name);
  80.     free (path);
  81.     free (args);
  82. }
  83. /*
  84.     Return != 0 if this is a valid record.
  85. */
  86. PUBLIC int DAEMON::isok()
  87. {
  88.     return name != NULL;
  89. }
  90.  
  91.  
  92. /*
  93.     Execute a command using the shell with loging in /tmp/netconf.log
  94. */
  95. int netconf_system (const char *cmd)
  96. {
  97.     /* #Specification: netconf / starting daemons / log
  98.         The file /var/adm/netconf.log is updated each time netconf
  99.         start or stop a daemon.
  100.     */
  101.     net_prtlog (MSG_U(X_EXECUTING,"Executing :%s\n"),cmd);
  102.     int ret = 0;
  103.     if (!simul_ison()){
  104.         int old_uid = getuid();
  105.         int old_euid = geteuid();
  106.         setuid (old_euid);
  107.         ret = system (cmd);
  108.         setreuid (old_uid,old_euid);
  109.         net_prtlog ("          return %d\n",ret);
  110.     }
  111.     return ret;
  112. }
  113. /*
  114.     Execute a command using the shell with loging in /tmp/netconf.log
  115.     The name of the command is used to located more info in /etc/conf.daemons.
  116.  
  117.     The command is conditionally executed if netconf is allowed to
  118.     managed this command.
  119. */
  120. int netconf_system_if (const char *name, const char *args)
  121. {
  122.     int ret = -1;
  123.     DAEMON *dae = daemon_find (name);
  124.     if (dae != NULL){
  125.         ret = 0;
  126.         char buf[1000];
  127.         sprintf (buf,"%s %s",dae->getpath(),args);
  128.         if (dae->is_managed()){
  129.             ret = netconf_system(buf);
  130.         }else if (!simul_ison()){
  131.             net_prtlog (MSG_U(X_WOULDEXEC,"Would have executed :%s\n"),buf);
  132.         }
  133.     }
  134.     return ret;
  135. }
  136. /*
  137.     Execute a command using the shell.
  138.     Return 0 if ok, != 0 if any error.
  139.  
  140.     This function is there to allows extension such as loging, debugging
  141.     etc.
  142. */
  143. PUBLIC int DAEMON::system(const char *cmd)
  144. {
  145.     return netconf_system (cmd);
  146. }
  147.  
  148. /*
  149.     start the daemon without much questionning.
  150.     Return -1 if any error.
  151. */
  152. PUBLIC VIRTUAL int DAEMON::start()
  153. {
  154.     int ret = 0;
  155.     if (!exist()){
  156.         if (!simul_ison()){
  157.             net_prtlog (MSG_U(X_MISSWOULDHAVE,"Program missing: Would have started %s\n")
  158.                 ,name);
  159.         }
  160.     }else{
  161.         char buf[2000];
  162.         sprintf (buf,"%s %s",path,args);
  163.         ret = system (buf);
  164.     }
  165.     return ret;
  166. }
  167. /*
  168.     Stop a daemon if it is running with a given signal number.
  169.     Return -1 if any error, -2 if no process alive, 0 if signal sent
  170. */
  171. PUBLIC int DAEMON::signal(
  172.     int signal_num,
  173.     const char *msg,
  174.     const char *sem_file)    // File used to remember when we
  175.                 // did issued the last signal
  176.                 // Or NULL if we don't care
  177. {
  178.     int ret = -2;
  179.     PROC *prc = process_find (path);
  180.     if (prc != NULL){
  181.         if (simul_ison()){
  182.             ret = 0;
  183.         }else{
  184.             ret = prc->kill (signal_num);
  185.             if (sem_file != NULL){
  186.                 int fd = creat (sem_file,0666);
  187.                 if (fd != -1) close (fd);
  188.             }
  189.         }
  190.         net_prtlog (MSG_U(X_SIGNALING,"%s %s with signal %d return %d\n")
  191.             ,msg,path,signal_num,ret);
  192.     }
  193.     return ret;
  194. }
  195. /*
  196.     Stop a daemon if it is running with a given signal number.
  197.     Return -1 if any error, -2 if no process alive, 0 if signal sent
  198. */
  199. PUBLIC int DAEMON::signal(
  200.     int signal_num,
  201.     const char *msg)
  202. {
  203.     return signal(signal_num,msg,NULL);
  204. }
  205.  
  206. /*
  207.     Stop a daemon if it is running with a given signal number.
  208.     Return -1 if any error.
  209. */
  210. PUBLIC int DAEMON::kill(int signal_num)
  211. {
  212.     int ret = 0;
  213.     for (int i=1; i<=3; i++){
  214.         if (process_find(path)==NULL){
  215.             break;
  216.         }else if (i==1){
  217.             ret = signal (signal_num,"Killing");
  218.             if (ret == -2 || simul_ison()) break;
  219.         }
  220.         sleep(i);
  221.         process_read();
  222.     }
  223.     return ret;
  224. }
  225. /*
  226.     Stop a daemon if it is running.
  227.  
  228.     The default is to use signal SIGTERM. This function is virtual.
  229.     Return -1 if any error.
  230. */
  231. PUBLIC VIRTUAL int DAEMON::stop()
  232. {
  233.     return kill (SIGTERM);
  234. }
  235. /*
  236.     A daemon may be restart normally by killing it and starting it.
  237.     It may be different for some daemon...
  238.  
  239.     Return -1 if any error.
  240. */
  241. PUBLIC VIRTUAL int DAEMON::restart()
  242. {
  243.     int ret = stop();
  244.     if (ret != -1) ret = start();
  245.     return ret;
  246. }
  247.  
  248. /*
  249.     Start or stop a daemon depending of the content of a configuration file.
  250.     If the file is younger than the process, the process is restarted.
  251. */
  252. PUBLIC int DAEMON::startif_file (const char *fname)
  253. {
  254.     long date = file_date (fname);
  255.     if (date != -1){
  256.         int empty = file_empty(fname);
  257.         if (empty) date = -1;
  258.     }
  259.     return startif_date (date);
  260. }
  261. /*
  262.     Start or stop a daemon depending of the content of a configuration file.
  263.     If the file is younger than the process, the process is restarted.
  264. */
  265. PUBLIC int DAEMON::startif_file (const CONFIG_FILE &cfile)
  266. {
  267.     return startif_file (cfile.getpath());
  268. }
  269. /*
  270.     Restart, start or stop a daemon if he is older than a date.
  271.     If the date is <= 0, it means that the corresponding configuration
  272.     file do not exist or is empty, so the daemon must be stopped.
  273. */
  274. PUBLIC int DAEMON::startif_date (long date)
  275. {
  276.     PROC *prc = process_find(path);
  277.     int ret = 0;
  278.     if (prc == NULL){
  279.         if (date > 0){
  280.             ret = start();
  281.         }
  282.     }else if (date <= 0){
  283.         ret = stop();
  284.     }else if (date > prc->getstarttime()){
  285.         ret = restart();
  286.     }
  287.     return ret;
  288. }
  289.  
  290.  
  291. /*        
  292.     start the daemon if not active or restart it if needed.
  293.     The daemon won't be started if not configured (Missing configuration
  294.     file).
  295.  
  296.     The default behavior (virtual function) is to start it if it
  297.     not already active.
  298.  
  299.     Return 0 = Was already active, 1 = started, 2 = not needed and
  300.         -1 = some error.
  301. */
  302. PUBLIC VIRTUAL int DAEMON::startif()
  303. {
  304.     PROC *prc = process_find (path);
  305.     int ret = 0;
  306.     if (prc == NULL){
  307.         ret = start() != -1 ? 1 : -1;
  308.     }
  309.     return ret;
  310. }
  311. /*
  312.     Return the name (not the path) of a daemon
  313. */
  314. PUBLIC const char *DAEMON::getname()
  315. {
  316.     return name;
  317. }
  318. /*
  319.     Return the next daemon in the link list or NULL.
  320. */
  321. PUBLIC DAEMON *DAEMON::getnext()
  322. {
  323.     return next;
  324. }
  325. /*
  326.     Return the path of a command or daemon.
  327. */
  328. PUBLIC const char *DAEMON::getpath()
  329. {
  330.     return path != NULL ? path : (name != NULL ? name : "");
  331. }
  332. /*
  333.     Return != 0 if the daemon exist on disk
  334. */
  335. PUBLIC int DAEMON::exist()
  336. {
  337.     int ret = 0;
  338.     if (path != NULL){
  339.          struct stat st;
  340.         ret = stat (path,&st) != -1;
  341.     }
  342.     return ret;
  343. }
  344. /*
  345.     Return the standard args of a command or daemon.
  346. */
  347. PUBLIC const char *DAEMON::getargs()
  348. {
  349.     return args != NULL ? args : "";
  350. }
  351.  
  352.  
  353. /*
  354.     Return != 0 if the daemon or command is managed by netconf.
  355.     The user may choose to manage some deamon with his own script.
  356. */
  357. PUBLIC int DAEMON::is_managed()
  358. {
  359.     return managed;
  360. }
  361. /*
  362.     Return != 0 if the daemon or command has been modified by the admin
  363.     (either the path of the command or the arguments)
  364. */
  365. PUBLIC int DAEMON::is_overriden()
  366. {
  367.     return override;
  368. }
  369.  
  370. /*
  371.     Set the managed flag.
  372. */
  373. PUBLIC void DAEMON::set_managed(int _managed)
  374. {
  375.     managed = (char)_managed;
  376. }
  377. /*
  378.     Set the override flag.
  379. */
  380. PUBLIC void DAEMON::set_override(int _over)
  381. {
  382.     override = (char)_over;
  383. }
  384.  
  385. /*
  386.     Set the specs of the daemon
  387. */
  388. PUBLIC void DAEMON::setspec(const char *_path, const char *_args)
  389. {
  390.     free (path);
  391.     free (args);
  392.     path = strdup(_path);
  393.     args = strdup(_args);
  394. }
  395.  
  396.  
  397.  
  398. /*
  399.     Write one record of the ETC_CONF_DAEMONS file.
  400. */
  401. PUBLIC void DAEMON::write(FILE *fout)
  402. {
  403.     if (isok()){
  404.         fprintf (fout,"%s%s %s %s\n"
  405.             ,managed ? "" : "!"
  406.             ,name,path,args);
  407.     }else{
  408.         fprintf (fout,"%s\n",managed ? "" : "!");
  409.     }
  410. }
  411.  
  412.  
  413.